package com.acxy.ants.core;

import com.acxy.ants.common.kit.JsonMap;
import com.acxy.ants.core.exception.TipException;
import com.acxy.ants.core.kit.EntityKit;
import com.acxy.ants.core.kit.ParamTypeKit;
import com.acxy.ants.resful.MappingMatch;
import com.acxy.ants.resful.RequestMapping;
import com.acxy.ants.resful.annotation.Entity;
import com.acxy.ants.resful.annotation.Param;
import com.acxy.ants.resful.annotation.PathVariable;
import com.acxy.ants.resful.bind.BindingResult;
import com.acxy.ants.resful.bind.LocalVariableTableParameterNameDiscoverer;
import com.alibaba.fastjson.JSON;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import javax.servlet.http.Part;
import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.regex.Pattern;

/**
 * 参数绑定并且进行数据校验
 *
 * @author MrShun
 * @version 1.0
 * @Date 2017-06-16
 */
public class BindingParams {

    private final static LocalVariableTableParameterNameDiscoverer u = new LocalVariableTableParameterNameDiscoverer();

    public static Object[] bingingValidate(String target, RequestMapping result, HttpServletRequest request, HttpServletResponse response) throws Exception {
        Method method = result.getMethod();
        //迭代方法参数类型
        Class<?>[] parameterTypes = method.getParameterTypes();
        if(parameterTypes.length == 0) return null;
        //定义参数数组并且绑定变量
        Object[] args = new Object[parameterTypes.length];
        //获取参数名称
        String[] params = u.getParameterNames(method);
        //定义错误消息
        List<String> errMsgs = new ArrayList<>();
        //给方法参数赋值
        outterLoop:
        for (int i = 0; i < parameterTypes.length; i++) {
            Class parameterType = parameterTypes[i];
            if (parameterType == HttpServletRequest.class)
                args[i] = request;
            else if (parameterType == HttpServletResponse.class)
                args[i] = response;
            else if (parameterType == HttpSession.class)
                args[i] = request.getSession();
            else if (parameterType == Part.class || parameterType == Part[].class) {
                if (parameterType.isArray()) {
                    args[i] = request.getParts().toArray();
                } else {
                    args[i] = request.getPart(params[i]);
                }
            }else if (parameterType == Map.class || parameterType == HashMap.class)
                args[i] = request.getParameterMap();
            else if (parameterType == JsonMap.class) {
                Map<String, String[]> parameterMap = request.getParameterMap();
                JsonMap jsonMap = JsonMap.newJsonMap();
                for(Map.Entry<String, String[]> entry: parameterMap.entrySet())
                    jsonMap.put(entry.getKey(), entry.getValue()[0]);
                args[i] = jsonMap;
            }else {
                //获取方法参数注解并进行校验
                Annotation[][] annotations = method.getParameterAnnotations();
                if (annotations.length > 0) {
                    for (int j = 0; j < annotations[i].length; j++) {
                        Annotation annotation = annotations[i][j];

                        //处理PathVariable注解, 将URL变量参数绑定到方法参数上面
                        if (annotation instanceof PathVariable) {
                            Map<String, String> uriValues = MappingMatch.getURIValues(result.getCurrentUrl(), target);
                            if (uriValues != null) {
                                String pathValue = ((PathVariable) annotation).value();
                                String val = "".equals(pathValue) ? uriValues.get(params[i]) : uriValues.get(pathValue);
                                if (parameterType.isArray()) {
                                    args[i] = ParamTypeKit.parse(new String[]{val}, parameterType);
                                } else {
                                    args[i] = ParamTypeKit.parse(val, parameterType);
                                }
                                continue outterLoop;
                            }
                        }

                        //处理Param注解, 参数校验
                        if (annotation instanceof Param) {
                            Param param = (Param) annotation;
                            String paramValue = param.value();
                            String[] parameterValues = request.getParameterValues(params[i]);
                            if (parameterValues == null || parameterValues.length == 0) { //Param注解
                                if(param.msg()==null || "".equals(param.msg()))
                                    errMsgs.add("the request '"+params[i]+"' parameter cannot be missing");
                                else
                                    errMsgs.add(param.msg());
                            } else {
                                if (!"".equals(paramValue)) { //有正则表达式
                                    String msg = param.msg()==null?"the request '"+params[i]+"'  parameter validate is not passed":param.msg();
                                    if (parameterType.isArray()) {
                                        for (String parameterValue : parameterValues) {
                                            if (!Pattern.matches(paramValue, parameterValue))
                                                errMsgs.add(msg);
                                               // throw new HandlerException(msg);
                                        }
                                        args[i] = ParamTypeKit.parse(parameterValues, parameterType);
                                    } else {
                                        if (!Pattern.matches(paramValue, parameterValues[0]))
                                            errMsgs.add(msg);
                                            //throw new HandlerException(msg);
                                        else
                                            args[i] = ParamTypeKit.parse(parameterValues[0], parameterType);
                                    }
                                } else {
                                    if (parameterType.isArray())
                                        args[i] = ParamTypeKit.parse(parameterValues, parameterType);
                                    else args[i] = ParamTypeKit.parse(parameterValues[0], parameterType);
                                }
                            }
                            continue outterLoop;
                        }
                    }
                }

                //发现对象是实体对象的时候
                if (parameterType.getAnnotation(Entity.class) != null) {
                    Object entityObj = null;
                    try {
                        entityObj = parameterType.newInstance();
                    } catch (InstantiationException e) {
                        e.printStackTrace();
                    } catch (IllegalAccessException e) {
                        e.printStackTrace();
                    }
                    Field[] fields = parameterType.getDeclaredFields();
                    for (Field field : fields) {
                        EntityKit.optSetMethod(field, request.getParameterValues(field.getName()), entityObj, errMsgs);
                    }
                    args[i] = entityObj;
                } else {
                    //判断参数是否为数组
                    String[] parameterValues = parameterType.isArray()?request.getParameterValues(params[i]+"[]"):request.getParameterValues(params[i]);
                    if (parameterValues != null) {
                        if (parameterType.isArray()) {
                            args[i] = JSON.parseObject(JSON.toJSONString(ParamTypeKit.parse(parameterValues, parameterType)), parameterType);
                        } else
                            args[i] = ParamTypeKit.parse(parameterValues[0], parameterType);
                    } else { //处理基本数据类型情况
                        if (parameterType.isPrimitive()) {
                            args[i] = ParamTypeKit.setDefault(parameterType);
                        }
                    }
                }
            }
        }
        //绑定错误消息
        if (parameterTypes[parameterTypes.length-1] == BindingResult.class)
            args[parameterTypes.length - 1] = new BindingResult(errMsgs);
        else
            if(errMsgs != null && errMsgs.size() > 0) throw new TipException(errMsgs.get(0));
        return args;
    }
}
